/*
** navigate.c
**
** Ed, Version 1.51, Copyright (c) 1992-94 SoftCircuits
** Redistributed by permission.
*/

#include <stdio.h>
#include <pictor.h>
#include "ed.h"

/*
** shows the current row/column on the status bar
*/
void show_status()
{
	xprintf(statusbar,"%-24.24s\xB3 <F1>=Help  <F10>=Exit  [%c]  "
		"%s  Row %-6dCol %-5d",filename,(modified) ? '*' : ' ',
		(insert_mode) ? "INS" : "OVR",file_row + 1,file_col + 1);

} /* show_status */

/*
** displays one line of text at the specified row
*/
void show_line(LINE *line,int row)
{
	int i,col,tab_cols;

	vcolor(edit_color);
	setvpos(row,edit_left);

	/* scan line up to point visible on screen */
	col = 0;
	for(i = 0;col < left_col && i < line->len;i++) {
		if(line->text[i] == '\t')
			col = NEXT_TAB(col);
		else col++;
	}

	/* write out any unfinished tab */
	if(col > left_col)
		vrepc(' ',col - left_col);

	/* write visible portion of line */
	for( ;col < (left_col + EDIT_COLS)
		&& i < line->len;i++) {

		if(line->text[i] == '\t') {
			tab_cols = (tab_size - (col % tab_size));
			if((col + tab_cols) > (left_col + EDIT_COLS))
				tab_cols = ((left_col + EDIT_COLS) - col);
			vrepc(' ',tab_cols);
			col += tab_cols;
		}
		else {
			vputc(line->text[i]);
			col++;
		}
	}

	/* fill remaining columns with spaces */
	if(col < (left_col + EDIT_COLS))
		vrepc(' ',(left_col + EDIT_COLS) - ((col > left_col) ? col : left_col));

} /* show_line */

/*
** repaints the edit window
*/
void show_text()
{
	int i;
	LINE *line = top_line;

	/* write line buffers */
	for(i = edit_top;i <= edit_bottom && line;i++) {
		show_line(line,i);
		line = line->next;
	}

	/* clear remaining lines (if any) */
	for( ;i <= edit_bottom;i++) {
		setvpos(i,edit_left);
		vrepc(' ',EDIT_COLS);
	}

} /* show_text */

/*
** sets file_col to represent line_ndx
*/
void set_file_col()
{
	int i;

	/* count columns up to line_ndx */
	for(file_col = 0,i = 0;i < line_ndx;i++) {
		if(curr_line->text[i] == '\t')
			file_col = NEXT_TAB(file_col);
		else
			file_col++;
	}

} /* set_file_col */

/*
** sets line_ndx to represent pref_col
** if pref_col exceeds the number of line columns,
** line_ndx is set to the end of the line
*/
void set_line_ndx()
{
	int col = 0;

	/* count line index up to pref_col */
	for(line_ndx = 0;line_ndx < curr_line->len;line_ndx++) {
		if(curr_line->text[line_ndx] == '\t')
			col = NEXT_TAB(col);
		else
			col++;
		if(col > pref_col)
			break;
	}

} /* set_line_ndx */

/*
** updates the edit cursor
** screen is updated if indicated by update_state
** horizontal scrolling is performed if required
**
** if set_pref_col is non-zero, the preferred
** column (pref_col) is set to match file_col
*/
void update_cursor(int set_pref_col)
{
	/* determine actual column */
	set_file_col();

	/* make current column the preferred column */
	if(set_pref_col)
		pref_col = file_col;

	/* check for horizontal scroll */
	if(file_col < left_col) {
		left_col = file_col;
		update_state = UPDATE_REPAINT;
	}
	else if((file_col - EDIT_COLS) >= left_col) {
		left_col = ((file_col - EDIT_COLS) + 1);
		update_state = UPDATE_REPAINT;
	}

	/* update screen */
	switch(update_state) {
		case UPDATE_REPAINT:
			show_text();
			break;
		case UPDATE_SCROLLUP:
			vcolor(edit_color);
			scroll(1,edit_top,edit_left,EDIT_ROWS,EDIT_COLS);
			show_line(curr_line,edit_bottom);
			break;
		case UPDATE_SCROLLDN:
			vcolor(edit_color);
			scroll(-1,edit_top,edit_left,EDIT_ROWS,EDIT_COLS);
			show_line(curr_line,edit_top);
			break;
	}

	/* set cursor position */
	setcurs((file_row - top_row) + edit_top,
		(file_col - left_col) + edit_left);

	/* update status bar */
	show_status();

	update_state = UPDATE_NOUPDATE;

} /* update_cursor */

/*
** moves left one character -- screen is not updated
*/
void _left()
{
	if(line_ndx > 0) {
		/* move left */
		line_ndx--;
	}
	else if(curr_line->prev != NULL) {
		/* wrap to previous line */
		_up();
		line_ndx = curr_line->len;
	}

} /* _left */

/*
** moves right one character -- screen is not updated
*/
void _right()
{
	if(line_ndx < curr_line->len) {
		/* move right */
		line_ndx++;
	}
	else if(curr_line->next != NULL) {
		/* wrap to next line */
		_down();
		line_ndx = 0;
	}

} /* _right */

/*
** moves up one line -- screen is not updated
*/
void _up()
{
	curr_line = curr_line->prev;
	file_row--;

	/* scroll if required */
	if(file_row < top_row) {
		top_line = top_line->prev;
		top_row--;
		update_state = UPDATE_SCROLLDN;
	}

	/* set line_ndx to match column in previous line */
	set_line_ndx();

} /* _up */

/*
** moves down one line -- screen is not updated
*/
void _down()
{
	curr_line = curr_line->next;
	file_row++;

	/* scroll if required */
	if((file_row - top_row) >= EDIT_ROWS) {
		top_line = top_line->next;
		top_row++;
		update_state = UPDATE_SCROLLUP;
	}

	/* set line_ndx to match column in previous line */
	set_line_ndx();

} /* _down */

/*
** moves one character left
*/
void cursor_left()
{
	if(line_ndx > 0 || curr_line->prev != NULL) {
		_left();
		update_cursor(TRUE);
	}
} /* cursor_left */

/*
** moves one character right
*/
void cursor_right()
{
	if(line_ndx < curr_line->len || curr_line->next != NULL) {
		_right();
		update_cursor(TRUE);
	}
} /* cursor_left */

/*
** moves one line up
*/
void cursor_up()
{
	if(curr_line->prev != NULL) {
		_up();
		update_cursor(FALSE);
	}
} /* cursor_up */

/*
** moves one line down
*/
void cursor_down()
{
	if(curr_line->next != NULL) {
		_down();
		update_cursor(FALSE);
	}
} /* cursor_down */

/*
** moves up one screen
*/
void page_up()
{
	int i;

	if(curr_line->prev != NULL) {
		/* change cursor position */
		for(i = 0;curr_line->prev != NULL && i < EDIT_ROWS;i++) {
			curr_line = curr_line->prev;
			file_row--;
		}
		/* change scroll position */
		if(top_line->prev != NULL) {
			for(i = 0;top_line->prev != NULL && i < EDIT_ROWS;i++) {
				top_line = top_line->prev;
				top_row--;
			}
			update_state = UPDATE_REPAINT;
		}

		/* set line_ndx to match column in prev line */
		set_line_ndx();
		update_cursor(FALSE);
	}

} /* page_up */

/*
** moves down one screen
*/
void page_down()
{
	int i;

	if(curr_line->next != NULL) {
		/* change cursor position */
		for(i = 0;curr_line->next != NULL && i < EDIT_ROWS;i++) {
			curr_line = curr_line->next;
			file_row++;
		}
		/* change scroll position */
		if(top_line->next != NULL) {
			for(i = 0;top_line->next != NULL && i < EDIT_ROWS;i++) {
				top_line = top_line->next;
				top_row++;
			}
			update_state = UPDATE_REPAINT;
		}

		/* set line_ndx to match column in prev line */
		set_line_ndx();
		update_cursor(FALSE);
	}

} /* page_down */

/*
** moves to the start of the first line
*/
void file_home()
{
	/* if not already at file home */
	if(curr_line->prev != NULL || file_col > 0) {
		/* set displayed lines */
		if(top_line->prev != NULL) {
			top_line = head;
			top_row = 0;
			update_state = UPDATE_REPAINT;
		}

		/* set current line */
		curr_line = head;
		file_row = 0;
		line_ndx = 0;
		update_cursor(TRUE);
	}

} /* file_home */

/*
** moves to the end of the last line
*/
void file_end()
{
	/* if not already at file end */
	if(curr_line->next != NULL || file_col < curr_line->len) {
		/* set displayed lines */
		if(top_line->next != NULL) {
			top_line = tail;
			top_row = (num_lines - 1);
			update_state = UPDATE_REPAINT;
		}

		/* set current line */
		curr_line = tail;
		file_row = (num_lines - 1);
		line_ndx = curr_line->len;
		update_cursor(TRUE);
	}

} /* file_end */

#ifdef EXT_ED


#endif
